<?php

namespace nabu\models\userModel;

defined('NABU') || exit;

require_once 'database/database.php';

use PDOException, nabu\database\database\database;

class userModel extends database {
  public function __construct() {
    parent::__construct();
  }

  // Busca un usuario dado su 'apodo' y 'dirección de e-mail';
  // @return un array asociativo de usuarios con su 'id', 'estado de cuenta',
  // y 'tiempo de expiración del token'.
  public function find_user(string $username, string $email) {
    $query = 'SELECT u.id, u.activated, v.expiration AS token_expiration FROM users AS u ' .
             'LEFT JOIN verifications AS v ON u.id = v.id WHERE u.username = ? OR u.email = ? LIMIT 2';

    try {
      $result = $this -> pdo -> prepare($query);

      $result -> execute(array($username, $email));

      return $result -> fetchAll();
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para validar si tu apodo y dirección de correo electrónico son únicos');
    }
  }

  // Elimina un usuario dado su 'id'.
  public function delete_user(int $id) {
    $query = 'DELETE FROM users WHERE id = ?';

    try {
      $this -> pdo -> prepare($query) -> execute(array($id));
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para eliminar una cuenta de usuario');
    }
  }

  // Registra un nuevo usuario en la base de datos.
  public function save_user(array $data) {
    $query = 'INSERT INTO users(name, username, email, password, creation_date) VALUES(:name, :username, :email, :password, :creation_date)';

    $data['creation_date'] = $this -> current_date();

    try {
      $this -> pdo -> prepare($query) -> execute($data);
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para registrar tu cuenta de usuario');
    }
  }

  // Busca y retorna el 'id' de un usuario dado el 'nombre de la columna' y el dato.
  public function user_id(string $column, $data) {
    $query = 'SELECT id FROM users WHERE ' . $column . ' = ? LIMIT 1';

    try {
      $result = $this -> pdo -> prepare($query);

      $result -> execute(array($data));

      $user = $result -> fetch();

      if ($user)
        return $user['id'];

      return $user;
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para buscar tu cuenta de usuario');
    }
  }

  // Registra el 'hash de verificación de dirección de e-mail' con tiempo de expiración.
  public function user_verifications(int $id, string $hash) {
    $query = 'INSERT INTO verifications(id, hash, expiration) VALUES(?, ?, ?)';

    try {
      $this -> pdo -> prepare($query) -> execute(array($id, $hash, time() + 60 * 60));
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para generar tu clave de verificación de dirección de correo electrónico');
    }
  }

  // Busca la 'verificación de dirección de e-mail' de un usuario dado su apodo;
  // @return el 'id', 'e-mail', 'tiempo de expiración del token'
  // y el 'hash de verificación'.
  public function find_verifications(string $username) {
    $query = 'SELECT u.id, u.email, v.hash AS token, v.expiration AS token_expiration ' .
             'FROM users AS u LEFT JOIN verifications AS v ON u.id = v.id ' .
             'WHERE u.username = ? LIMIT 1';

    try {
      $result = $this -> pdo -> prepare($query);

      $result -> execute(array($username));

      return $result -> fetch();
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para confirmar tu dirección de correo electrónico');
    }
  }

  // Activa la cuenta de un usuario dato su 'id'.
  public function activate_account(int $id) {
    $query = 'UPDATE users SET activated = TRUE WHERE id = ?';

    try {
      $this -> pdo -> prepare($query) -> execute(array($id));
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para activar tu cuenta de usuario');
    }
  }

  // Elimina la 'verificación de dirección de e-mail' de un usuario dado su 'id'.
  public function delete_verification(int $id) {
    $query = 'DELETE FROM verifications WHERE id = ?';

    try {
      $this -> pdo -> prepare($query) -> execute(array($id));
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para activar tu cuenta de usuario');
    }
  }

  // Crea un 'perfil de usuario' dado su 'id'.
  public function create_profile(int $id) {
    $query = 'INSERT INTO profiles(id) VALUES(?)';

    try {
      $this -> pdo -> prepare($query) -> execute(array($id));
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para activar tu cuenta de usuario');
    }
  }

  // Busca un usuario dado el 'nombre de la columna' y el tipo de identificación;
  // @return un array asociativo con el 'id', 'role', 'contraseña', 'estado de cuenta',
  // y 'tiempo de expiración' del usuario.
  public function user_access(string $column, string $identity) {
    $query = 'SELECT u.id, u.username, u.password, u.role_id AS role, u.activated, v.expiration AS token_expiration FROM users AS u ' .
             'LEFT JOIN verifications AS v ON u.id = v.id WHERE u.' . $column . ' = ? LIMIT 1';

    try {
      $result = $this -> pdo -> prepare($query);

      $result -> execute(array($identity));

      return $result -> fetch();
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para validar tus credenciales de acceso');
    }
  }

  // Busca un perfil de usuario dado el 'nombre de la columna' y el dato de coincidencia;
  // @return un array asociativo con el 'nombre', 'apodo', 'foto de perfil', 'fondo de perfil' y 'descripción'.
  public function find_profile(string $column, $data) {
    $query = 'SELECT u.name, u.username, p.avatar, p.background, p.description FROM users AS u INNER JOIN profiles AS p ON u.id = p.id ' .
             'WHERE u.' . $column . ' = ? LIMIT 1';

    try {
      $result = $this -> pdo -> prepare($query);

      $result -> execute(array($data));

      return $result -> fetch();
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para mostrar los datos del perfil de usuario');
    }
  }

  // Actualiza los datos de un usuario dado su 'id' y los datos a actualizar.
  public function update_user(int $id, array $data) {
    $keys  = array_keys($data);
    $query = '';

    foreach ($keys as $key)
      $query = $query . $key . ' = :' . $key . ', ';

    $query = 'UPDATE users SET ' . rtrim($query, ', ') . ' WHERE id = :id';

    $data['id'] = $id;

    try {
      $this -> pdo -> prepare($query) -> execute($data);
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para actualizar tus datos personales');
    }
  }

  // Busca una imagen de perfil dado el 'nombre de la columna' y el 'nombre del archivo';
  // @return el 'id' de una imagen.
  public function find_image(string $column, string $filename) {
    $query = 'SELECT id FROM profiles WHERE ' . $column . ' = ? LIMIT 1';

    try {
      $result = $this -> pdo -> prepare($query);

      $result -> execute(array($filename));

      $image = $result -> fetch();

      if ($image)
        return $image['id'];

      return $image;
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para buscar tus imágenes de perfil');
    }
  }

  // Actualiza los datos de perfil de un usuario dado su 'id' y los datos a actualizar.
  public function update_profile(int $id, array $data) {
    $keys  = array_keys($data);
    $query = '';

    foreach ($keys as $key)
      $query = $query . $key . ' = :' . $key . ', ';

    $query = 'UPDATE profiles SET ' . rtrim($query, ', ') . ' WHERE id = :id';

    $data['id'] = $id;

    try {
      $this -> pdo -> prepare($query) -> execute($data);
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para actualizar los datos de tu perfil');
    }
  }

  // @return el 'hash' de la contraseña, la 'foto de perfil' y el 'fondo del perfil'.
  public function find_password(int $id) {
    $query = 'SELECT u.password, p.avatar, p.background FROM users AS u INNER JOIN profiles AS p ON u.id = p.id ' .
             'WHERE u.id = ? LIMIT 1';

    try {
      $result = $this -> pdo -> prepare($query);

      $result -> execute(array($id));

      return $result -> fetch();
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para validar tu contraseña');
    }
  }

  // Elimina el perfil de un usuario.
  public function delete_profile(int $id) {
    $query = 'DELETE FROM profiles WHERE id = ?';

    try {
      $this -> pdo -> prepare($query) -> execute(array($id));
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para eliminar tu cuenta de usuario');
    }
  }

  // Borra la dirección de e-mail y desactiva la cuenta de un usuario dado su 'id'.
  public function delete_account(int $id) {
    $query = 'UPDATE users SET email = NULL, activated = FALSE WHERE id = ?';

    try {
      $this -> pdo -> prepare($query) -> execute(array($id));
    }
    catch(PDOException $e) {
      $this -> errors($e -> getMessage(), 'tuvimos un problema para eliminar tu dirección de correo electrónico');
    }
  }

  public function __destruct() {
    parent::__destruct();
  }
}
